817
20678
تشرح كتب لغة البرمجة أن أنواع القيم يتم إنشاؤها على المكدس ، وأن أنواع المراجع يتم إنشاؤها على الكومة ، دون توضيح ماهية هذين الأمرين. لم أقرأ شرحًا واضحًا لهذا الأمر. أنا أفهم ما هو المكدس. لكن،
أين وماذا هم (ماديا في ذاكرة الكمبيوتر الحقيقية)؟
إلى أي مدى يتم التحكم فيها بواسطة نظام التشغيل أو وقت تشغيل اللغة؟
ما هو نطاقها؟
ما الذي يحدد حجم كل منها؟
ما الذي يجعل المرء أسرع؟ 
المكدس هو الذاكرة الموضوعة جانباً كمساحة خدش لسلسلة من التنفيذ. عندما يتم استدعاء وظيفة ، يتم حجز كتلة في الجزء العلوي من المكدس للمتغيرات المحلية وبعض بيانات مسك الدفاتر. عندما تعود هذه الوظيفة ، تصبح الكتلة غير مستخدمة ويمكن استخدامها في المرة التالية التي يتم فيها استدعاء الوظيفة. يتم حجز المكدس دائمًا بترتيب LIFO (آخر ما يرد أولاً) ؛ أحدث كتلة محجوزة هي دائمًا الكتلة التالية التي سيتم تحريرها. هذا يجعل من السهل حقًا تتبع المكدس ؛ تحرير كتلة من المكدس ليس أكثر من تعديل مؤشر واحد.
الكومة هي الذاكرة المخصصة للتخصيص الديناميكي. على عكس المكدس ، لا يوجد نمط مفروض لتخصيص وإلغاء تخصيص الكتل من الكومة ؛ يمكنك تخصيص كتلة في أي وقت وتحريرها في أي وقت. هذا يجعل الأمر أكثر تعقيدًا لتتبع أجزاء الكومة المخصصة أو المجانية في أي وقت ؛ هناك العديد من مخصصات الكومة المخصصة المتاحة لضبط أداء الكومة لأنماط استخدام مختلفة.
يحصل كل خيط على مكدس ، بينما عادة ما يكون هناك كومة واحدة فقط للتطبيق (على الرغم من أنه ليس من غير المألوف أن يكون لديك أكوام متعددة لأنواع مختلفة من التخصيص).
للإجابة على أسئلتك مباشرة:
إلى أي مدى يتم التحكم فيها بواسطة نظام التشغيل أو وقت تشغيل اللغة؟
يخصص نظام التشغيل المكدس لكل مؤشر ترابط على مستوى النظام عند إنشاء الخيط. عادةً ما يتم استدعاء نظام التشغيل بواسطة وقت تشغيل اللغة لتخصيص الكومة للتطبيق.
ما هو نطاقها؟
يتم إرفاق المكدس بخيط ، لذلك عندما يخرج الخيط يتم استرداد المكدس. عادةً ما يتم تخصيص الكومة عند بدء تشغيل التطبيق بحلول وقت التشغيل ، ويتم استعادتها عند إنهاء التطبيق (المعالجة الفنية).
ما الذي يحدد حجم كل منها؟
يتم تعيين حجم المكدس عند إنشاء سلسلة. يتم تعيين حجم الكومة عند بدء تشغيل التطبيق ، ولكن يمكن أن يزداد حسب الحاجة إلى مساحة (يطلب المخصص ذاكرة أكبر من نظام التشغيل).
ما الذي يجعل المرء أسرع؟
يكون المكدس أسرع لأن نمط الوصول يجعل تخصيص الذاكرة وإلغاء تخصيصها منه أمرًا تافهًا (المؤشر / العدد الصحيح يتزايد ببساطة أو يتناقص) ، في حين أن الكومة لديها مسك دفاتر أكثر تعقيدًا متضمنًا في التخصيص أو إلغاء التخصيص. أيضًا ، يميل كل بايت في المكدس إلى إعادة استخدامه بشكل متكرر مما يعني أنه يميل إلى التعيين في ذاكرة التخزين المؤقت للمعالج ، مما يجعله سريعًا جدًا. نتيجة أخرى لأداء الكومة هي أن الكومة ، كونها في الغالب مورد عالمي ، يجب أن تكون آمنة متعددة مؤشرات الترابط ، أي يجب أن يكون كل تخصيص وإلغاء تخصيص - عادةً - متزامنين مع "جميع" عمليات الوصول إلى الكومة الأخرى في البرنامج.
مظاهرة واضحة:
مصدر الصورة: vikashazrati.wordpress.com
|
كومة:
مخزنة في ذاكرة الوصول العشوائي للكمبيوتر تمامًا مثل الكومة.
ستخرج المتغيرات التي تم إنشاؤها في المكدس خارج النطاق وسيتم إلغاء تخصيصها تلقائيًا.
أسرع بكثير في التخصيص بالمقارنة مع المتغيرات الموجودة على الكومة.
تم تنفيذه بهيكل بيانات مكدس فعلي.
يخزن البيانات المحلية وعناوين الإرجاع المستخدمة لتمرير المعلمات.
يمكن أن يكون هناك تجاوز للمكدس عند استخدام قدر كبير جدًا من المكدس (غالبًا من العودية اللانهائية أو العميقة جدًا ، عمليات تخصيص كبيرة جدًا).
يمكن استخدام البيانات التي تم إنشاؤها على المكدس بدون مؤشرات.
يمكنك استخدام المكدس إذا كنت تعرف بالضبط مقدار البيانات التي تحتاج إلى تخصيصها قبل وقت الترجمة وهي ليست كبيرة جدًا.
عادةً ما يكون الحد الأقصى للحجم محددًا بالفعل عند بدء البرنامج.
كومة:
مخزنة في ذاكرة الوصول العشوائي للكمبيوتر تمامًا مثل المكدس.
في لغة C ++ ، يجب تدمير المتغيرات الموجودة في الكومة يدويًا ولا تخرج عن النطاق أبدًا. يتم تحرير البيانات مع حذف أو حذف [] أو مجانًا.
أبطأ في التخصيص بالمقارنة مع المتغيرات على المكدس.
تستخدم عند الطلب لتخصيص كتلة من البيانات ليستخدمها البرنامج.
يمكن أن يكون هناك تجزئة عندما يكون هناك الكثير من عمليات التخصيص وإلغاء التخصيصات.
في C ++ أو C ، سيتم الإشارة إلى البيانات التي تم إنشاؤها على الكومة بواسطة مؤشرات وتخصيصها باستخدام new أو malloc على التوالي.
يمكن أن يكون هناك فشل في التخصيص إذا تم طلب تخصيص مخزن مؤقت كبير جدًا.
يمكنك استخدام الكومة إذا كنت لا تعرف بالضبط مقدار البيانات التي ستحتاجها في وقت التشغيل أو إذا كنت بحاجة إلى تخصيص الكثير من البيانات.
مسؤول عن تسرب الذاكرة.
مثال:
int foo ()
{
شار * pBuffer ؛ // <- لم يتم تخصيص أي شيء حتى الآن (باستثناء المؤشر نفسه ، المخصص هنا في المكدس).
منطقي ب = صحيح ؛ // مخصص على المكدس.
إذا (ب)
{
// أنشئ 500 بايت على المكدس
عازلة شار [500] ؛
// إنشاء 500 بايت على الكومة
pBuffer = حرف جديد [500] ؛
} // <- تم إلغاء تخصيص المخزن المؤقت هنا ، ولكن pBuffer ليس كذلك
} // <--- عفوًا ، هناك تسرب للذاكرة ، كان ينبغي عليّ استدعاء حذف [] pBuffer؛
|
النقطة الأكثر أهمية هي أن الكومة والمكدس عبارة عن مصطلحات عامة للطرق التي يمكن بها تخصيص الذاكرة. يمكن تنفيذها بعدة طرق مختلفة ، وتنطبق المصطلحات على المفاهيم الأساسية.
في كومة من العناصر ، توضع العناصر واحدة فوق الأخرى بالترتيب الذي تم وضعها هناك ، ويمكنك فقط إزالة العنصر العلوي(دون إسقاط كل شيء).
تتمثل بساطة المكدس في أنك لا تحتاج إلى الاحتفاظ بجدول يحتوي على سجل لكل قسم من أقسام الذاكرة المخصصة ؛ معلومات الحالة الوحيدة التي تحتاجها هي مؤشر واحد لنهاية المكدس. للتخصيص وإلغاء التخصيص ، ما عليك سوى زيادة هذا المؤشر الفردي وتقليله. ملاحظة: يمكن أحيانًا تنفيذ المكدس للبدء في الجزء العلوي من قسم الذاكرة والتوسع إلى أسفل بدلاً من النمو لأعلى.
في الكومة ، لا يوجد ترتيب معين لطريقة وضع العناصر. يمكنك الوصول إلى العناصر وإزالتها بأي ترتيب لأنه لا يوجد عنصر "علوي" واضح.
يتطلب تخصيص الكومة الاحتفاظ بسجل كامل لما يتم تخصيصه وما هو غير ذلك ، بالإضافة إلى بعض الصيانة العامة لتقليل التجزئة ، والعثور على مقاطع ذاكرة متجاورة كبيرة بما يكفي لتناسب الحجم المطلوب ، وما إلى ذلك. يمكن إلغاء تخصيص الذاكرة في أي وقت مع ترك مساحة خالية. في بعض الأحيان ، يقوم مُخصص الذاكرة بتنفيذ مهام الصيانة مثل إلغاء تجزئة الذاكرة عن طريق تحريك الذاكرة المخصصة ، أو جمع البيانات المهملة - تحديد وقت التشغيل عندما لا تكون الذاكرة في النطاق وإلغاء تخصيصها.
يجب أن تقوم هذه الصور بعمل جيد إلى حد ما لوصف طريقتين لتخصيص وتحرير الذاكرة في مكدس وكومة. يم!
إلى أي مدى يتم التحكم فيها بواسطة نظام التشغيل أو وقت تشغيل اللغة؟
كما ذكرنا ، فإن الكومة والمكدس عبارة عن مصطلحات عامة ، ويمكن تنفيذها بعدة طرق. تحتوي برامج الكمبيوتر عادةً على مكدس يسمى مكدس الاستدعاءات الذي يخزن المعلومات ذات الصلة بالوظيفة الحالية مثل المؤشر لأي وظيفة تم استدعاءها منها وأي متغيرات محلية. نظرًا لأن الوظائف تستدعي وظائف أخرى ثم تعود ، فإن المكدس ينمو ويتقلص للاحتفاظ بالمعلومات من الوظائف إلى أسفل مكدس الاستدعاءات. لا يمتلك البرنامج حقًا التحكم في وقت التشغيل ؛ يتم تحديده من خلال لغة البرمجة ونظام التشغيل وحتى بنية النظام.
الكومة هي مصطلح عام يستخدم لأي ذاكرة يتم تخصيصها ديناميكيًا وعشوائيًا ؛ أي خارج الترتيب. يتم تخصيص الذاكرة عادةً بواسطة نظام التشغيل ، مع استدعاء التطبيق لوظائف API للقيام بهذا التخصيص. هناك قدر لا بأس به من النفقات الإضافية المطلوبة في إدارة الذاكرة المخصصة ديناميكيًا ، والتي يتم التعامل معها عادةً من خلال رمز وقت تشغيل لغة البرمجة أو البيئة المستخدمة.
ما هو نطاقها؟
تعتبر مكدس الاستدعاءات مفهومًا منخفض المستوى بحيث لا يتعلق بـ "النطاق" بمعنى البرمجة. إذا قمت بتفكيك بعض التعليمات البرمجية ، فسترى إشارات نسبية لنمط المؤشر لأجزاء من المكدس ، ولكن فيما يتعلق بلغة المستوى الأعلى ، فإن اللغة تفرض قواعد النطاق الخاصة بها. ومع ذلك ، فإن أحد الجوانب المهمة للمكدس هو أنه بمجرد إرجاع دالة ، يتم تحرير أي شيء محلي لهذه الوظيفة على الفور من المكدس. هذا يعمل بالطريقة التي تتوقعها أن تعمل بالنظر إلى كيفية عمل لغات البرمجة الخاصة بك. في الكومة ، من الصعب أيضًا تحديدها. النطاق هو كل ما يعرضه نظام التشغيل ، ولكن ربما تضيف لغة البرمجة الخاصة بك قواعدها حول ماهية "النطاق" في تطبيقك. تستخدم بنية المعالج ونظام التشغيل عنونة افتراضية ، والتي يترجمها المعالج إلى عناوين فعلية وهناك أخطاء في الصفحة ، وما إلى ذلك. فهم يتتبعون الصفحات التي تنتمي إلى أي تطبيقات. لا داعي للقلق بشأن هذا أبدًا ، لأنك تستخدم أي طريقة تستخدمها لغة البرمجة لتخصيص الذاكرة وتحريرها ، والتحقق من الأخطاء (إذا فشل التخصيص / التحرير لأي سبب).
ما الذي يحدد حجم كل منها؟
مرة أخرى ، يعتمد الأمر على اللغة والمترجم ونظام التشغيل والهندسة المعمارية. عادةً ما يتم تخصيص المكدس مسبقًا ، لأنه بحكم التعريف يجب أن يكون ذاكرة متجاورة. يحدد مترجم اللغة أو نظام التشغيل حجمه. لا تقوم بتخزين أجزاء ضخمة من البيانات على المكدس ، لذلك ستكون كبيرة بما يكفي بحيث لا يجب استخدامها بالكامل ، باستثناء حالات التكرار اللانهائي غير المرغوب فيه (ومن ثم ، "تجاوز سعة المكدس") أو قرارات البرمجة غير العادية الأخرى.
الكومة هي مصطلح عام لأي شيء يمكن تخصيصه ديناميكيًا. اعتمادًا على الطريقة التي تنظر بها إليه ، يتغير الحجم باستمرار. في المعالجات وأنظمة التشغيل الحديثة ، الطريقة الدقيقة التي تعمل بها مجردة للغاية على أي حال ، لذلك لا داعي للقلق كثيرًا بشأن كيفية عملها في العمق ، باستثناء أنه (في اللغات التي تتيح لك ذلك) يجب ألا تستخدم ذاكرة لم تخصصها بعد أو الذاكرة التي قمت بتحريرها.
ما الذي يجعل المرء أسرع؟
يكون المكدس أسرع لأن كل الذاكرة الخالية متلاصقة دائمًا. لا يلزم الاحتفاظ بقائمة لجميع أجزاء الذاكرة الخالية ، فقط مؤشر واحد إلى الجزء العلوي الحالي من المكدس. يقوم المترجمون عادةً بتخزين هذا المؤشر في سجل خاص وسريع لهذا الغرض. علاوة على ذلك ، عادةً ما تتركز العمليات اللاحقة على المكدس داخل مناطق قريبة جدًا من الذاكرة ، والتي تكون عند مستوى منخفض جدًا جيدة للتحسين بواسطة المعالج عند الموتمخابئ.
|
(لقد نقلت هذه الإجابة من سؤال آخر كان أكثر أو أقل خداعًا لهذا السؤال).
الإجابة على سؤالك خاصة بالتنفيذ وقد تختلف باختلاف المجمعين وبنيات المعالج. ومع ذلك ، هنا شرح مبسط.
كل من المكدس والكومة عبارة عن مناطق ذاكرة مخصصة من نظام التشغيل الأساسي (غالبًا ذاكرة افتراضية يتم تعيينها للذاكرة الفعلية عند الطلب).
في بيئة متعددة الخيوط ، سيكون لكل مؤشر ترابط مكدس مستقل تمامًا خاص به ، لكنه سيشترك في الكومة. يجب التحكم في الوصول المتزامن على الكومة وهو غير ممكن في المكدس.
الكومة
تحتوي الكومة على قائمة مرتبطة بالكتل المستخدمة والمجانية. يتم استيفاء التخصيصات الجديدة على الكومة (بواسطة new أو malloc) بإنشاء كتلة مناسبة من إحدى الكتل المجانية. هذا يتطلب تحديث قائمة الكتل على الكومة. يتم أيضًا تخزين معلومات التعريف هذه حول الكتل الموجودة على الكومة على الكومة غالبًا في منطقة صغيرة أمام كل كتلة.
مع نمو الكومة ، غالبًا ما يتم تخصيص الكتل الجديدة من العناوين الأقل نحو العناوين الأعلى. وبالتالي يمكنك التفكير في الكومة على أنها كومة من كتل الذاكرة التي تنمو في الحجم مع تخصيص الذاكرة. إذا كانت الكومة صغيرة جدًا بالنسبة للتخصيص ، فيمكن غالبًا زيادة الحجم عن طريق الحصول على ذاكرة أكبر من نظام التشغيل الأساسي.
قد يؤدي تخصيص العديد من الكتل الصغيرة وإلغاء تخصيصها إلى ترك الكومة في حالة يوجد بها الكثير من الكتل الحرة الصغيرة المتناثرة بين الكتل المستخدمة. قد يفشل طلب تخصيص كتلة كبيرة نظرًا لعدم وجود أي من الكتل الحرة كبيرة بما يكفي لتلبية طلب التخصيص على الرغم من أن الحجم المجمع للكتل الحرة قد يكون كبيرًا بدرجة كافية. يسمى هذا تجزئة الكومة.
عندما يتم إلغاء تخصيص كتلة مستخدمة مجاورة للكتلة الحرة ، يمكن دمج الكتلة الحرة الجديدة مع الكتلة الحرة المجاورة لإنشاء كتلة حرة أكبر مما يقلل بشكل فعال تجزئة الكومة.
المدخنة
غالبًا ما يعمل المكدس جنبًا إلى جنب مع سجل خاص على وحدة المعالجة المركزية يسمى مؤشر المكدس. في البداية يشير مؤشر المكدس إلى أعلى المكدس (أعلى عنوان في المكدس).
تحتوي وحدة المعالجة المركزية على تعليمات خاصة لدفع القيم إلى المكدس وإعادتها من المكدس. تقوم كل دفعة بتخزين القيمة في الموقع الحالي لمؤشر المكدس وتقليل مؤشر المكدس. يسترد المنبثق القيمة التي يشير إليها مؤشر المكدس ثم يزيد مؤشر المكدس (لا تخلط بينك وبين حقيقة أن إضافة قيمة إلى المكدس يقلل مؤشر المكدس ويزيده إزالة القيمة. تذكر أن المكدس ينمو القاع). القيم المخزنة والمستردة هي قيم سجلات وحدة المعالجة المركزية.
عندما يتم استدعاء وظيفة ، تستخدم وحدة المعالجة المركزية تعليمات خاصة تدفع مؤشر التعليمات الحالي ، أي عنوان الكود المنفذ على المكدس. ثم تنتقل وحدة المعالجة المركزية إلى الوظيفة عن طريق ضبط ملف
يسمى مؤشر التعليمات إلى عنوان الوظيفة. في وقت لاحق ، عندما تعود الوظيفة ، يظهر مؤشر التعليمات القديم من المكدس ويستأنف التنفيذ في الكود بعد استدعاء الوظيفة مباشرة.
عند إدخال وظيفة ، يتم تقليل مؤشر المكدس لتخصيص مساحة أكبر على المكدس للمتغيرات المحلية (التلقائية). إذا كانت الوظيفة تحتوي على متغير محلي واحد 32 بت ، يتم وضع أربعة بايتات جانباً في المكدس. عندما تعود الوظيفة ، يتم تحريك مؤشر المكدس للخلف لتحرير المنطقة المخصصة.
إذا كانت الوظيفة تحتوي على معلمات ، يتم دفعها إلى المكدس قبل استدعاء الوظيفة. عندئذٍ يكون الرمز الموجود في الوظيفة قادرًا على التنقل لأعلى في المكدس من مؤشر المكدس الحالي لتحديد هذه القيم.
تعمل مكالمات وظيفة التعشيش مثل السحر. ستخصص كل مكالمة جديدة معلمات الوظيفة وعنوان الإرجاع والمساحة للمتغيرات المحلية ويمكن تكديس سجلات التنشيط هذه للمكالمات المتداخلة وستفك بالطريقة الصحيحة عند عودة الوظائف.
نظرًا لأن المكدس عبارة عن كتلة محدودة من الذاكرة ، يمكنك التسبب في تجاوز سعة المكدس عن طريق استدعاء العديد من الوظائف المتداخلة و / أو تخصيص مساحة كبيرة جدًا للمتغيرات المحلية. غالبًا ما يتم إعداد منطقة الذاكرة المستخدمة للمكدس بطريقة تجعل الكتابة أسفل أسفل (أدنى عنوان) للمكدس تؤدي إلى تشغيل فخ أو استثناء في وحدة المعالجة المركزية. يمكن بعد ذلك اكتشاف هذا الشرط الاستثنائي في وقت التشغيل وتحويله إلى نوع من استثناء تجاوز سعة المكدس.
هل يمكن تخصيص وظيفة على الكومة بدلاً من مكدس؟
لا ، يتم تخصيص سجلات التنشيط للوظائف (أي المتغيرات المحلية أو التلقائية) في المكدس الذي لا يستخدم فقط لتخزين هذه المتغيرات ، ولكن أيضًا لتتبع استدعاءات الوظائف المتداخلة.
كيف تتم إدارة الكومة يعود حقًا إلى بيئة وقت التشغيل. يستخدم C استخدام malloc و C ++ يستخدم جديدًا ، لكن العديد من اللغات الأخرى بها مجموعة بيانات غير صحيحة.
ومع ذلك ، فإن المكدس هو ميزة منخفضة المستوى مرتبطة ارتباطًا وثيقًا بهندسة المعالج. إن زيادة الكومة عندما لا توجد مساحة كافية ليس بالأمر الصعب منذ ذلك الحينيمكن تنفيذه في استدعاء المكتبة الذي يعالج الكومة. ومع ذلك ، فإن نمو المكدس غالبًا ما يكون مستحيلًا حيث يتم اكتشاف تجاوز المكدس فقط عند فوات الأوان ؛ وإغلاق خيط التنفيذ هو الخيار الوحيد القابل للتطبيق.
|
في كود C # التالي
طريقة الفراغ العام 1 ()
{
int أنا = 4 ؛
int y = 2 ؛
class1 cls1 = new class1 () ؛
}
إليك كيفية إدارة الذاكرة
المتغيرات المحلية التي يجب أن تستمر فقط طالما أن استدعاء الوظيفة موجود في المكدس. يتم استخدام الكومة للمتغيرات التي لا نعرف حقًا عمرها مقدمًا ولكننا نتوقع أن تستمر لفترة. في معظم اللغات ، من المهم أن نعرف في وقت الترجمة حجم المتغير إذا أردنا تخزينه على المكدس.
الكائنات (التي تختلف في الحجم أثناء تحديثها) تنتقل إلى الكومة لأننا لا نعرف في وقت الإنشاء كم من الوقت ستستمر. في العديد من اللغات ، تكون الكومة عبارة عن القمامة التي تم جمعها للعثور على كائنات (مثل الكائن cls1) التي لم يعد لها أي مراجع.
في Java ، تذهب معظم الكائنات مباشرة إلى الكومة. في لغات مثل C / C ++ ، غالبًا ما تظل البنيات والفئات في المكدس عندما لا تتعامل مع المؤشرات.
ويمكن الاطلاع على مزيد من المعلومات هنا:
الفرق بين الكومة وتخصيص الذاكرة الكومة «timmurphy.org
و هنا:
إنشاء كائنات على المكدس والكومة
هذه المقالة هي مصدر الصورة أعلاه: ستة مفاهيم مهمة لـ .NET: التكديس ، الكومة ، أنواع القيم ، أنواع المراجع ، الملاكمة ، وإلغاء الصندوق - CodeProject
لكن كن على علم أنه قد يحتوي على بعض عدم الدقة.
|
المدخنة
عند استدعاء دالة ، يتم وضع الوسائط الخاصة بهذه الوظيفة بالإضافة إلى بعض النفقات العامة الأخرى على المكدس. يتم أيضًا تخزين بعض المعلومات (مثل إلى أين تذهب عند العودة) هناك.
عندما تعلن عن متغير داخل وظيفتك ، يتم تخصيص هذا المتغير أيضًا في المكدس.
يعد إلغاء تخصيص المكدس أمرًا بسيطًا جدًا لأنك تقوم دائمًا بإلغاء التخصيص بالترتيب العكسي الذي تخصصه. تتم إضافة عناصر المكدس عند إدخال الوظائف ، تتم إزالة البيانات المقابلة عند الخروج منها. هذا يعني أنك تميل إلى البقاء داخل منطقة صغيرة من المكدس ما لم تستدعي الكثير من الوظائف التي تستدعي الكثير من الوظائف الأخرى (أو تنشئ حلًا تعاوديًا).
الكومة
الكومة هي اسم عام للمكان الذي تضع فيه البيانات التي تقوم بإنشائها بسرعة. إذا كنت لا تعرف عدد سفن الفضاء التي سيقوم برنامجك بإنشائها ، فمن المحتمل أن تستخدم عامل التشغيل الجديد (أو malloc أو ما يعادله) لإنشاء كل سفينة فضائية. سيستمر هذا التخصيص لبعض الوقت ، لذلك من المحتمل أن نحرر الأشياء بترتيب مختلف عما أنشأناه.
وبالتالي ، فإن الكومة أكثر تعقيدًا بكثير ، لأنه ينتهي بها الأمر إلى وجود مناطق من الذاكرة غير مستخدمة مع أجزاء متناثرة - تتفتت الذاكرة. يعد العثور على ذاكرة خالية بالحجم الذي تحتاجه مشكلة صعبة. هذا هو السبب في أنه يجب تجنب الكومة (على الرغم من أنها لا تزال تستخدم في كثير من الأحيان).
التنفيذ
عادة ما يكون تنفيذ كل من المكدس والكومة إلى وقت التشغيل / نظام التشغيل. غالبًا ما تنشئ الألعاب والتطبيقات الأخرى ذات الأهمية الحاسمة للأداء حلول ذاكرة خاصة بها تستحوذ على جزء كبير من الذاكرة من الكومة ثم تقوم بإخراجها داخليًا لتجنب الاعتماد على نظام التشغيل للذاكرة.
يكون هذا عمليًا فقط إذا كان استخدامك للذاكرة مختلفًا تمامًا عن المعتاد - أي بالنسبة للألعاب التي تقوم فيها بتحميل مستوى في عملية واحدة ضخمة ويمكنك التخلص من كل شيء بعيدًا في عملية ضخمة أخرى.
الموقع المادي في الذاكرة
هذا أقل أهمية مما تعتقد بسبب تقنية تسمى Virtual Memory تجعل برنامجك يعتقد أنه يمكنك الوصول إلى عنوان معين حيث تكون البيانات المادية في مكان آخر (حتى على القرص الصلب!). يتم ترتيب العناوين التي تحصل عليها للمكدس بشكل متزايد مع تعمق شجرة الاتصال الخاصة بك. لا يمكن التنبؤ بعناوين الكومة (أي محددة بالتطبيق) وبصراحة ليست مهمة.
|
للتوضيح ، تحتوي هذه الإجابة على معلومات غير صحيحة (قام توماس بإصلاح إجابته بعد التعليقات ، رائع :)). الإجابات الأخرى فقط تتجنب شرح معنى التخصيص الثابت. لذلك سأشرح الأشكال الثلاثة الرئيسية للتخصيص وكيف ترتبط عادةً بمقطع الكومة والمكدس والبيانات أدناه. سأعرض أيضًا بعض الأمثلة في كل من C / C ++ و Python لمساعدة الناس على الفهم.
لا يتم تخصيص المتغيرات "الثابتة" (المخصصة بشكل ثابت AKA) في المكدس. لا تفترض ذلك - فالكثير من الناس يفعلون ذلك فقط لأن كلمة "ثابت" تبدو مثل كلمة "مكدس". هم في الواقع لا توجد في المكدس ولا الكومة. جزء مما يسمى مقطع البيانات.
ومع ذلك ، فمن الأفضل عمومًا النظر في "النطاق" و "العمر" بدلاً من "المكدس" و "الكومة".
يشير النطاق إلى أجزاء الكود التي يمكنها الوصول إلى متغير. بشكل عام ، نفكر في النطاق المحلي (لا يمكن الوصول إليه إلا من خلال الوظيفة الحالية) مقابل النطاق العالمي (يمكن الوصول إليه في أي مكان) على الرغم من أن النطاق يمكن أن يصبح أكثر تعقيدًا.
يشير مصطلح Lifetime إلى الوقت الذي يتم فيه تخصيص متغير وإلغاء تخصيصه أثناء تنفيذ البرنامج. عادة ما نفكر في تخصيص ثابت (متغيرسيستمر طوال مدة البرنامج بالكامل ، مما يجعله مفيدًا لتخزين نفس المعلومات عبر عدة استدعاءات للوظائف) مقابل التخصيص التلقائي (يستمر المتغير فقط أثناء استدعاء واحد لوظيفة ، مما يجعله مفيدًا لتخزين المعلومات التي يتم استخدامها فقط أثناء وظيفة ويمكن إهمالها بمجرد الانتهاء) مقابل التخصيص الديناميكي (المتغيرات التي يتم تحديد مدتها في وقت التشغيل ، بدلاً من وقت التجميع مثل الثابت أو التلقائي).
على الرغم من أن معظم المترجمين والمترجمين الفوريين ينفذون هذا السلوك بشكل مشابه من حيث استخدام التكديس والأكوام وما إلى ذلك ، فقد يكسر المترجم أحيانًا هذه الاصطلاحات إذا أراد طالما كان السلوك صحيحًا. على سبيل المثال ، بسبب التحسين ، قد يوجد متغير محلي فقط في سجل أو يمكن إزالته بالكامل ، على الرغم من وجود معظم المتغيرات المحلية في المكدس. كما تمت الإشارة إليه في بعض التعليقات ، فأنت حر في تنفيذ مترجم لا يستخدم حتى مكدسًا أو كومة ، ولكن بدلاً من ذلك بعض آليات التخزين الأخرى (نادرًا ما يتم ذلك ، نظرًا لأن التكديس والأكوام رائعة لهذا الغرض).
سأقدم بعض كود C المشروح البسيط لتوضيح كل هذا. أفضل طريقة للتعلم هي تشغيل برنامج تحت مصحح الأخطاء ومشاهدة السلوك. إذا كنت تفضل قراءة لغة python ، فانتقل إلى نهاية الإجابة :)
// مخصص بشكل ثابت في مقطع البيانات عند تحميل البرنامج / DLL لأول مرة
// تم إلغاء تخصيصه عند إنهاء البرنامج / DLL
// النطاق - يمكن الوصول إليه من أي مكان في الكود
int بعضGlobalVariable؛
// المخصصة إحصائيًا في مقطع البيانات عند تحميل البرنامج لأول مرة
// تم إلغاء تخصيصه عند إنهاء البرنامج / DLL
// النطاق - يمكن الوصول إليه من أي مكان في ملف التعليمات البرمجية هذا
ثابت في بعض متغير ثابت ؛
// يتم تخصيص "someArgument" في المكدس في كل مرة يتم استدعاء MyFunction
يتم إلغاء تخصيص // "someArgument" عند إرجاع MyFunction
// النطاق - يمكن الوصول إليه فقط من خلال MyFunction ()
إلغاء وظيفتي (في بعض الوسيط) {
// المخصصة إحصائيًا في مقطع البيانات عند تحميل البرنامج لأول مرة
// تم إلغاء تخصيصه عند إنهاء البرنامج / DLL
// النطاق - يمكن الوصول إليه فقط من خلال MyFunction ()
ثابت في بعض متغير محلي ثابت ؛
// مخصص على المكدس في كل مرة يتم استدعاء MyFunction
// تم إلغاء تخصيصه عند عودة MyFunction
// النطاق - يمكن الوصول إليه فقط من خلال MyFunction ()
بعض المتغيرات المحلية
يتم تخصيص // A * pointer * في المكدس في كل مرة يتم استدعاء MyFunction
// يتم إلغاء تخصيص هذا المؤشر عند إرجاع MyFunction
// النطاق - لا يمكن الوصول إلى المؤشر إلا من خلال MyFunction ()
int * someDynamicVariable ؛
// يتسبب هذا السطر في تخصيص مساحة لعدد صحيح في الكومة
// عندما يتم تنفيذ هذا الخط. لاحظ أن هذا ليس في بداية
// استدعاء الوظيفة () ، مثل المتغيرات التلقائية
// النطاق - فقط الكود الموجود داخل MyFunction () يمكنه الوصول إلى هذه المساحة
// * من خلال هذا المتغير المحدد *.
// ومع ذلك ، إذا قمت بتمرير العنوان في مكان آخر ، فهذا الرمز
// يمكنه الوصول إليه أيضًا
someDynamicVariable = جديد int ؛
// هذا السطر يلغي تخصيص مساحة العدد الصحيح في الكومة.
// إذا لم نكتبها ، فسوف يتم "تسريب" الذاكرة.
// لاحظ اختلافًا جوهريًا بين المكدس والكومة
// يجب أن تدار الكومة. يتم إدارة المكدس بالنسبة لنا.
حذف someDynamicVariable ؛
// في حالات أخرى ، بدلاً من إلغاء تخصيص مساحة الكومة هذه
// قد يخزن العنوان في مكان أكثر ديمومة لاستخدامه لاحقًا.
// بعض اللغات تهتم بإلغاء التخصيص نيابة عنك ... لكن
// دائمًا يحتاج إلى العناية به في وقت التشغيل بواسطة بعض الآليات.
// عندما ترجع الدالة ، someArgument ، someLocalVariable
// ويتم إلغاء تخصيص المؤشر someDynamicVariable.
// المساحة المشار إليها بواسطة someDynamicVariable كانت بالفعل
// تم إلغاء تخصيصها قبل العودة.
إرجاع؛
}
// لاحظ أن someGlobalVariable و someStaticVariable و
// someLocalStaticVariable لا تزال موجودة ولكنها ليست كذلك
// إلغاء تخصيصه حتى انتهاء البرنامج.
أحد الأمثلة المؤثرة بشكل خاص على سبب أهمية التمييز بين العمر والنطاق هو أن المتغير يمكن أن يكون له نطاق محلي ولكن عمر ثابت - على سبيل المثال ، "someLocalStaticVariable" في نموذج التعليمات البرمجية أعلاه. يمكن لمثل هذه المتغيرات أن تجعل عادات التسمية الشائعة ولكن غير الرسمية مربكة للغاية. على سبيل المثال ، عندما نقول "محلي" فإننا نعني عادةً "متغير مخصص تلقائيًا محدد النطاق محليًا" وعندما نقول عالمي فإننا نعني عادةً "متغير مخصص ثابت النطاق عالميًا" لسوء الحظ عندما يتعلق الأمر بأشياء مثل "المتغيرات المخصصة بشكل ثابت في نطاق الملف" يقول الكثير من الناس ... "هاه ؟؟؟".
تؤدي بعض خيارات بناء الجملة في C / C ++ إلى تفاقم هذه المشكلة - على سبيل المثال يعتقد الكثير من الناس أن المتغيرات العالمية ليست "ثابتة" بسبب البنية الموضحة أدناه.
int var1 ؛ // له نطاق عالمي وتخصيص ثابت
ثابت int var2 ؛ // له نطاق ملف وتخصيص ثابت
int main () {return 0؛}
لاحظ أن وضع الكلمة الأساسية "static" في الإعلان أعلاه يمنع var2 من أن يكون له نطاق عالمي. ومع ذلك ، فإن var1 العالمي له تخصيص ثابت. هذا ليسحدسي! لهذا السبب ، أحاول عدم استخدام كلمة "ثابت" مطلقًا عند وصف النطاق ، وبدلاً من ذلك أقول شيئًا مثل نطاق "ملف" أو "ملف محدود". ومع ذلك ، يستخدم العديد من الأشخاص عبارة "ثابت" أو "نطاق ثابت" لوصف متغير لا يمكن الوصول إليه إلا من ملف رمز واحد. في سياق العمر ، تعني كلمة "ثابت" دائمًا أن المتغير يتم تخصيصه عند بدء البرنامج وإلغاء تخصيصه عند إنهاء البرنامج.
يعتقد بعض الناس أن هذه المفاهيم خاصة بـ C / C ++. هم ليسوا. على سبيل المثال ، يوضح نموذج Python أدناه جميع أنواع التخصيص الثلاثة (هناك بعض الاختلافات الدقيقة الممكنة في اللغات المفسرة والتي لن أتطرق إليها هنا).
من تاريخ استيراد ووقت وتاريخ
فئة الحيوان:
_FavoriteFood = "غير محدد" # _يتم توزيع الطعام المفضل بشكل ثابت
def PetAnimal (ذاتي):
curTime = datetime.time (datetime.now ()) يتم تخصيص # curTime تلقائيًا
print ("شكرًا لك على مداعبتي. لكنها" + str (curTime) + "، يجب أن تطعمني. طعامي المفضل هو" + self ._FavoriteFood)
فئة القط (حيوان):
_FavoriteFood = 'tuna' # ملاحظة نظرًا لأننا تجاوزنا ، فإن فئة Cat لها تخصيص ثابت خاص بها _FavoriteFood متغير ، يختلف عن Animal
فئة الكلب (حيوان):
_FavoriteFood = 'steak' # وبالمثل ، تحصل فئة Dog على المتغير الثابت الخاص بها. من المهم ملاحظة - هذا المتغير الثابت مشترك بين جميع حالات Dog ، وبالتالي فهو ليس ديناميكيًا!
إذا __name__ == "__main__":
شعيرات = Cat () # مخصصة ديناميكيًا
fido = Dog () # مخصص ديناميكيًا
rinTinTin = الكلب () # مخصص ديناميكيًا
شعيرات.
fido.PetAnimal ()
rinTin.PetAnimal ()
Dog._FavoriteFood = "عظام اللبن"
شعيرات.
fido.PetAnimal ()
rinTin.PetAnimal ()
# الإخراج هو:
# شكرا لك لملاعبتي. لكنها 13: 05: 02.255000 ، يجب أن تطعمني. طعامي المفضل هو التونة
# شكرا لك لملاعبتي. لكنها 13: 05: 02.255000 ، يجب أن تطعمني. طعامي المفضل هو شريحة لحم
# شكرا لك لملاعبتي. لكنها 13: 05: 02.255000 ، يجب أن تطعمني. طعامي المفضل هو شريحة لحم
# شكرا لك لملاعبتي. لكنها 13: 05: 02.255000 ، يجب أن تطعمني. طعامي المفضل هو التونة
# شكرا لك لملاعبتي. لكنها 13: 05: 02.255000 ، يجب أن تطعمني. طعامي المفضل هو عظام اللبن
# شكرا لك لملاعبتي. لكنها 13: 05: 02.256000 ، يجب أن تطعمني. طعامي المفضل هو عظام اللبن
|
أجاب الآخرون على الضربات العريضة بشكل جيد ، لذا سأقدم بعض التفاصيل.
لا يلزم أن يكون المكدس والكومة مفردين. الموقف الشائع الذي يكون لديك فيه أكثر من مكدس واحد هو إذا كان لديك أكثر من مؤشر ترابط واحد في العملية. في هذه الحالة ، يكون لكل خيط كومة خاصة به. يمكنك أيضًا الحصول على أكثر من كومة واحدة ، على سبيل المثال يمكن أن تؤدي بعض تكوينات DLL إلى تخصيص مكتبات DLL مختلفة من أكوام مختلفة ، وهذا هو السبب في أنه من الجيد عمومًا تحرير الذاكرة المخصصة بواسطة مكتبة مختلفة.
في C ، يمكنك الاستفادة من تخصيص الطول المتغير من خلال استخدام التخصيص ، الذي يخصص في المكدس ، بدلاً من التخصيص ، الذي يخصص على الكومة. لن تنجو هذه الذاكرة من بيان الإرجاع الخاص بك ، لكنها مفيدة لمخزن الخدش.
إن إنشاء مخزن مؤقت ضخم على Windows لا تستخدم الكثير منه ليس مجانيًا. هذا لأن المترجم سينشئ حلقة مسبار مكدس تسمى كل مرة يتم فيها إدخال وظيفتك للتأكد من وجود المكدس (لأن Windows يستخدم صفحة حماية واحدة في نهاية المكدس الخاص بك لاكتشاف متى يحتاج إلى زيادة المكدس. إذا قمت بالوصول إلى ذاكرة أكثر من صفحة واحدة من نهاية المكدس فسوف تتعطل). مثال:
وظيفتي باطلة ()
{
شار كبير [10000000] ؛
// افعل شيئًا يستخدم فقط لأول 1 كيلو من 99٪ من الوقت.
}
|
أجاب الآخرون على سؤالك مباشرةً ، ولكن عند محاولة فهم المكدس والكومة ، أعتقد أنه من المفيد التفكير في تخطيط الذاكرة لعملية UNIX التقليدية (بدون مؤشرات الترابط والمخصصات القائمة على mmap ()). تحتوي صفحة ويب مسرد إدارة الذاكرة على رسم تخطيطي لتخطيط الذاكرة هذا.
توجد المكدس والكومة بشكل تقليدي على طرفي نقيض لمساحة العنوان الافتراضية للعملية. ينمو المكدس تلقائيًا عند الوصول إليه ، حتى الحجم الذي تحدده النواة (والذي يمكن ضبطه باستخدام setrlimit (RLIMIT_STACK ، ...)) تنمو الكومة عندما يستدعي مخصص الذاكرة استدعاء النظام brk () أو sbrk () ، مما يؤدي إلى تعيين المزيد من صفحات الذاكرة الفعلية في مساحة العنوان الظاهرية للعملية.
في الأنظمة التي لا تحتوي على ذاكرة افتراضية ، مثل بعض الأنظمة المضمنة ، غالبًا ما يتم تطبيق نفس التخطيط الأساسي ، باستثناء أن حجم المكدس والكومة ثابتان. ومع ذلك ، في الأنظمة المضمنة الأخرى (مثل تلك التي تعتمد على ميكروكنترولر Microchip PIC) ، فإن مكدس البرنامج عبارة عن كتلة منفصلة من الذاكرة لا يمكن معالجتها بواسطة تعليمات حركة البيانات ، ولا يمكن تعديلها أو قراءتها إلا بشكل غير مباشر من خلال تعليمات تدفق البرنامج (استدعاء ، العودة ، وما إلى ذلك). تحتوي البنى الأخرى ، مثل معالجات Intel Itanium ، على حزم متعددة. بهذا المعنى ، فإن المكدس هو عنصر من عناصر بنية وحدة المعالجة المركزية.
|
المكدس جزءمن الذاكرة التي يمكن معالجتها عبر العديد من تعليمات لغة التجميع الرئيسية ، مثل 'pop' (إزالة قيمة وإرجاعها من المكدس) و 'push' (دفع قيمة إلى المكدس) ، ولكن أيضًا استدعاء (استدعاء روتين فرعي - يدفع العنوان للعودة إلى المكدس) والعودة (العودة من روتين فرعي - يؤدي هذا إلى إخراج العنوان من المكدس والانتقال إليه). إنها منطقة الذاكرة الموجودة أسفل سجل مؤشر المكدس ، والتي يمكن تعيينها حسب الحاجة. يتم استخدام المكدس أيضًا لتمرير الوسائط إلى الإجراءات الفرعية ، وكذلك للحفاظ على القيم في السجلات قبل استدعاء الإجراءات الفرعية.
الكومة هي جزء من الذاكرة يتم إعطاؤه لتطبيق ما بواسطة نظام التشغيل ، عادةً من خلال مكالمة نظام مثل malloc. في أنظمة التشغيل الحديثة ، هذه الذاكرة عبارة عن مجموعة من الصفحات التي يمكن فقط لعملية الاستدعاء الوصول إليها.
يتم تحديد حجم المكدس في وقت التشغيل ، ولا ينمو بشكل عام بعد إطلاق البرنامج. في برنامج C ، يجب أن يكون المكدس كبيرًا بما يكفي لاحتواء كل متغير تم الإعلان عنه داخل كل دالة. ستنمو الكومة ديناميكيًا حسب الحاجة ، لكن نظام التشغيل يقوم في النهاية بإجراء المكالمة (غالبًا ما يزيد الكومة بأكثر من القيمة التي يطلبها malloc ، بحيث لا يحتاج بعض malloc في المستقبل على الأقل إلى العودة إلى النواة إلى الحصول على المزيد من الذاكرة. غالبًا ما يكون هذا السلوك قابلاً للتخصيص)
نظرًا لأنك قمت بتخصيص المكدس قبل بدء تشغيل البرنامج ، فلن تحتاج أبدًا إلى malloc قبل أن تتمكن من استخدام المكدس ، لذا فهذه ميزة بسيطة هناك. من الناحية العملية ، من الصعب جدًا التنبؤ بما سيكون سريعًا وما سيكون بطيئًا في أنظمة التشغيل الحديثة التي تحتوي على أنظمة فرعية للذاكرة الافتراضية ، لأن كيفية تنفيذ الصفحات ومكان تخزينها هي تفاصيل تنفيذية.
|
ما هو المكدس؟
المكدس هو كومة من العناصر ، وعادة ما تكون مرتبة بدقة.
الأكوام في معماريات الحوسبة هي مناطق الذاكرة حيث تتم إضافة البيانات أو إزالتها بطريقة الوارد أخيرًا.
في تطبيق متعدد الخيوط ، سيكون لكل خيط مكدس خاص به.
ما هي الكومة؟
الكومة عبارة عن مجموعة غير مرتبة من الأشياء المتراكمة عشوائياً.
في معماريات الحوسبة ، تكون الكومة مساحة من الذاكرة المخصصة ديناميكيًا والتي تتم إدارتها تلقائيًا بواسطة نظام التشغيل أو مكتبة إدارة الذاكرة.
يتم تخصيص الذاكرة الموجودة على الكومة وإلغاء تخصيصها وتغيير حجمها بانتظام أثناء تنفيذ البرنامج ، وقد يؤدي ذلك إلى مشكلة تسمى التجزئة.
يحدث التجزئة عندما يتم تخصيص كائنات الذاكرة بمسافات صغيرة بينها أصغر من أن تحتوي على كائنات ذاكرة إضافية.
النتيجة الصافية هي نسبة من مساحة الكومة غير قابلة للاستخدام لعمليات تخصيص الذاكرة الإضافية.
الاثنين معا
في تطبيق متعدد الخيوط ، سيكون لكل خيط مكدس خاص به. ولكن ، ستشترك جميع الخيوط المختلفة في الكومة.
نظرًا لأن الخيوط المختلفة تشترك في الكومة في تطبيق متعدد الخيوط ، فهذا يعني أيضًا أنه يجب أن يكون هناك بعض التنسيق بين الخيوط حتى لا يحاولوا الوصول إلى نفس القطعة (الأجزاء) من الذاكرة في الكومة عند نفس الوقت.
أيهما أسرع - المكدس أم الكومة؟ و لماذا؟
المكدس أسرع بكثير من الكومة.
هذا بسبب الطريقة التي يتم بها تخصيص الذاكرة على المكدس.
يعد تخصيص الذاكرة على المكدس أمرًا بسيطًا مثل تحريك مؤشر المكدس لأعلى.
بالنسبة إلى الأشخاص الجدد في مجال البرمجة ، من الأفضل استخدام الحزمة لأنها أسهل.
نظرًا لأن المكدس صغير ، فقد ترغب في استخدامه عندما تعرف بالضبط مقدار الذاكرة التي ستحتاجها لبياناتك ، أو إذا كنت تعلم أن حجم بياناتك صغير جدًا.
من الأفضل استخدام الكومة عندما تعلم أنك ستحتاج إلى قدر كبير من الذاكرة لبياناتك ، أو أنك لست متأكدًا من مقدار الذاكرة التي ستحتاجها (مثل المصفوفة الديناميكية).
نموذج ذاكرة جافا
المكدس هو مساحة الذاكرة حيث يتم تخزين المتغيرات المحلية (بما في ذلك معلمات الطريقة). عندما يتعلق الأمر بمتغيرات الكائن ، فهذه مجرد مراجع (مؤشرات) للكائنات الفعلية الموجودة في الكومة.
في كل مرة يتم فيها إنشاء كائن ، يتم وضع جزء كبير من ذاكرة الكومة جانبًا للاحتفاظ ببيانات (حالة) هذا الكائن. نظرًا لأن الكائنات يمكن أن تحتوي على كائنات أخرى ، يمكن أن تحتوي بعض هذه البيانات في الواقع على مراجع لتلك الكائنات المتداخلة.
|
أعتقد أن العديد من الأشخاص الآخرين قدموا لك إجابات صحيحة في الغالب حول هذا الموضوع.
أحد التفاصيل التي تم تفويتها ، مع ذلك ، هو أن "الكومة" يجب أن تسمى في الواقع "المتجر المجاني". والسبب في هذا التمييز هو أن المخزن المجاني الأصلي تم تنفيذه باستخدام بنية بيانات تُعرف باسم "كومة ذات الحدين". لهذا السبب ، كان التخصيص من عمليات التنفيذ المبكرة لـ malloc () / free () عبارة عن تخصيص من كومة. ومع ذلك ، في هذا العصر الحديث ، يتم تنفيذ معظم المتاجر المجانية بهياكل بيانات معقدة للغاية ليست أكوام ذات حدين.
|
يمكنك القيام ببعض الأشياء المثيرة للاهتمام مع المكدس. على سبيل المثال ، لديك وظائف مثل التخصيص (بافتراض أنه يمكنك تجاوز التحذيرات الغزيرة المتعلقة باستخدامه) ، وهو شكل من أشكال malloc الذييستخدم على وجه التحديد المكدس ، وليس الكومة ، للذاكرة.
ومع ذلك ، فإن أخطاء الذاكرة القائمة على المكدس هي من أسوأ الأخطاء التي واجهتها. إذا كنت تستخدم ذاكرة الكومة ، وتجاوزت حدود الكتلة المخصصة لديك ، فلديك فرصة جيدة لإحداث خطأ في المقطع. (ليس 100٪: قد تكون الكتلة الخاصة بك متجاورة بشكل عرضي مع كتلة أخرى قمت بتخصيصها مسبقًا.) ولكن نظرًا لأن المتغيرات التي تم إنشاؤها في المكدس تكون دائمًا متجاورة مع بعضها البعض ، فإن الكتابة خارج الحدود يمكن أن تغير قيمة متغير آخر. لقد تعلمت أنه كلما شعرت أن برنامجي قد توقف عن إطاعة قوانين المنطق ، فمن المحتمل أن يكون ذلك هو تجاوز المخزن المؤقت.
|
ببساطة ، المكدس هو المكان الذي يتم فيه إنشاء المتغيرات المحلية. أيضًا ، في كل مرة تقوم فيها باستدعاء روتين فرعي ، عداد البرنامج (المؤشر إلى تعليمات الجهاز التالية) وأي سجلات مهمة ، وأحيانًا يتم دفع المعلمات على المكدس. ثم يتم دفع أي متغيرات محلية داخل الروتين الفرعي إلى المكدس (ويتم استخدامها من هناك). عند انتهاء الروتين الفرعي ، يتم إخراج كل هذه الأشياء من المكدس. يحصل الكمبيوتر الشخصي وبيانات التسجيل على ويعيدها إلى حيث كانت كما ظهرت ، حتى يتمكن برنامجك من المضي قدمًا في طريقه الممتع.
الكومة هي منطقة الذاكرة الديناميكية التي يتم تخصيصها من (مكالمات صريحة "جديدة" أو "تخصيص"). إنها بنية بيانات خاصة يمكنها تتبع كتل الذاكرة ذات الأحجام المختلفة وحالة تخصيصها.
في الأنظمة "الكلاسيكية" ، تم وضع ذاكرة الوصول العشوائي (RAM) بحيث يبدأ مؤشر المكدس في الجزء السفلي من الذاكرة ، ويبدأ مؤشر الكومة في الأعلى ، وينمو كل منهما تجاه الآخر. إذا تداخلوا ، فأنت خارج ذاكرة الوصول العشوائي. هذا لا يعمل مع أنظمة تشغيل حديثة متعددة الخيوط. يجب أن يكون لكل خيط مكدس خاص به ، ويمكن إنشاء تلك العناصر بشكل ديناميكي.
|
من WikiAnwser.
كومة
عندما تستدعي دالة أو طريقة وظيفة أخرى تستدعي بدورها وظيفة أخرى ، وما إلى ذلك ، يظل تنفيذ جميع هذه الوظائف معلقًا حتى ترجع الوظيفة الأخيرة قيمتها.
هذه السلسلة من استدعاءات الوظائف المعلقة هي المكدس ، لأن العناصر في المكدس (استدعاءات الوظائف) تعتمد على بعضها البعض.
المكدس مهم للنظر في معالجة الاستثناءات وعمليات تنفيذ مؤشر الترابط.
كومة
الكومة هي ببساطة الذاكرة التي تستخدمها البرامج لتخزين المتغيرات.
لا يحتوي عنصر الكومة (المتغيرات) على تبعيات مع بعضها البعض ويمكن دائمًا الوصول إليه بشكل عشوائي في أي وقت.
|
كومة
وصول سريع جدا
لا يتعين عليك إلغاء تخصيص المتغيرات بشكل صريح
تتم إدارة المساحة بكفاءة بواسطة وحدة المعالجة المركزية ، ولن يتم تجزئة الذاكرة
المتغيرات المحلية فقط
الحد من حجم المكدس (يعتمد على نظام التشغيل)
لا يمكن تغيير حجم المتغيرات
كومة
يمكن الوصول إلى المتغيرات عالميًا
لا حدود لحجم الذاكرة
(نسبيًا) وصول أبطأ
لا يوجد استخدام فعال مضمون للمساحة ، فقد تتفتت الذاكرة بمرور الوقت حيث يتم تخصيص كتل من الذاكرة ، ثم تحريرها
يجب عليك إدارة الذاكرة (أنت مسؤول عن تخصيص المتغيرات وتحريرها)
يمكن تغيير حجم المتغيرات باستخدام realloc ()
|
بالمختصر
يتم استخدام المكدس لتخصيص الذاكرة الثابتة وكومة لتخصيص الذاكرة الديناميكية ، وكلاهما مخزّن في ذاكرة الوصول العشوائي للكمبيوتر.
بالتفصيل
المدخنة
المكدس عبارة عن بنية بيانات "LIFO" (ما يرد أخيرًا يخرج أولاً) ، تتم إدارتها وتحسينها بواسطة وحدة المعالجة المركزية عن كثب. في كل مرة تعلن دالة عن متغير جديد ، يتم "دفعها" إلى المكدس. ثم في كل مرة يتم فيها الخروج من الوظيفة ، يتم تحرير جميع المتغيرات التي يتم دفعها إلى المكدس بواسطة هذه الوظيفة (أي يتم حذفها). بمجرد تحرير متغير المكدس ، تصبح منطقة الذاكرة هذه متاحة لمتغيرات المكدس الأخرى.
تتمثل ميزة استخدام المكدس لتخزين المتغيرات في أن الذاكرة تُدار من أجلك. لا يتعين عليك تخصيص الذاكرة يدويًا ، أو تحريرها بمجرد عدم الحاجة إليها بعد الآن. علاوة على ذلك ، نظرًا لأن وحدة المعالجة المركزية تنظم ذاكرة المكدس بكفاءة عالية ، فإن القراءة من المتغيرات والكتابة إليها تكون سريعة جدًا.
أكثر من ذلك يمكن العثور عليها هنا.
الكومة
الكومة هي منطقة من ذاكرة الكمبيوتر لا تتم إدارتها تلقائيًا نيابة عنك ، ولا تتم إدارتها بإحكام بواسطة وحدة المعالجة المركزية. إنها منطقة أكثر حرية في الذاكرة (وهي أكبر). لتخصيص ذاكرة على الكومة ، يجب عليك استخدام malloc () أو calloc () ، وهما دالات C مضمنة. بمجرد تخصيص الذاكرة على الكومة ، فأنت مسؤول عن استخدام free () لإلغاء تخصيص تلك الذاكرة بمجرد عدم الحاجة إليها بعد الآن.
إذا فشلت في القيام بذلك ، فسيحتوي برنامجك على ما يُعرف باسم تسرب الذاكرة. أي أن الذاكرة الموجودة في الكومة ستظل جانباً (ولن تكون متاحة للعمليات الأخرى). كما سنرى في قسم تصحيح الأخطاء ، هناك أداة تسمى Valgrind يمكنها مساعدتك في اكتشاف تسرب الذاكرة.
على عكس المكدس ، لا توجد قيود على حجم الكومة على الحجم المتغير (بصرف النظر عن القيود المادية الواضحة لجهاز الكمبيوتر الخاص بك). ذاكرة الكومة أبطأ قليلاً للقراءة منها والكتابة إليها ، لأنه يتعين على المرء استخدام المؤشرات للوصول إلى الذاكرة الموجودة على الكومة. سنتحدث عن المؤشرات قريبا.
على عكس المكدس ،يمكن الوصول إلى المتغيرات التي تم إنشاؤها على الكومة بواسطة أي وظيفة في أي مكان في برنامجك. متغيرات الكومة هي في الأساس عالمية في النطاق.
أكثر من ذلك يمكن العثور عليها هنا.
يتم تخزين المتغيرات المخصصة على المكدس مباشرة في الذاكرة والوصول إلى هذه الذاكرة سريع جدًا ، ويتم التعامل مع تخصيصها عند تجميع البرنامج. عندما تستدعي دالة أو طريقة وظيفة أخرى تستدعي بدورها وظيفة أخرى ، وما إلى ذلك ، يظل تنفيذ جميع هذه الوظائف معلقًا حتى ترجع الوظيفة الأخيرة قيمتها. يتم حجز المكدس دائمًا بترتيب LIFO ، وتكون الكتلة المحجوزة مؤخرًا هي دائمًا الكتلة التالية التي سيتم تحريرها. هذا يجعل من السهل حقًا تتبع المكدس ، وتحرير كتلة من المكدس ليس أكثر من ضبط مؤشر واحد.
يتم تخصيص ذاكرة المتغيرات المخصصة في الكومة في وقت التشغيل ويكون الوصول إلى هذه الذاكرة أبطأ قليلاً ، لكن حجم الكومة يقتصر فقط على حجم الذاكرة الظاهرية. لا تحتوي عناصر الكومة على تبعيات مع بعضها البعض ويمكن دائمًا الوصول إليها بشكل عشوائي في أي وقت. يمكنك تخصيص كتلة في أي وقت وتحريرها في أي وقت. هذا يجعل الأمر أكثر تعقيدًا لتتبع أجزاء الكومة المخصصة أو المجانية في أي وقت.
يمكنك استخدام المكدس إذا كنت تعرف بالضبط مقدار البيانات التي تحتاج إلى تخصيصها قبل وقت الترجمة ، وهي ليست كبيرة جدًا. يمكنك استخدام الكومة إذا كنت لا تعرف بالضبط مقدار البيانات التي ستحتاجها في وقت التشغيل أو إذا كنت بحاجة إلى تخصيص الكثير من البيانات.
في الوضع متعدد الخيوط ، سيكون لكل مؤشر ترابط مكدس مستقل تمامًا خاص به ، لكنهم سيشاركون الكومة. المكدس خاص بمؤشر الترابط والكومة خاصة بالتطبيق. المكدس مهم للنظر في معالجة الاستثناءات وعمليات تنفيذ مؤشر الترابط.
يحصل كل خيط على مكدس ، بينما عادة ما يكون هناك كومة واحدة فقط للتطبيق (على الرغم من أنه ليس من غير المألوف أن يكون لديك أكوام متعددة لأنواع مختلفة من التخصيص).
في وقت التشغيل ، إذا احتاج التطبيق إلى مزيد من الكومة ، فيمكنه تخصيص ذاكرة من الذاكرة الخالية وإذا احتاج المكدس إلى ذاكرة ، فيمكنه تخصيص ذاكرة من الذاكرة الفارغة المخصصة للتطبيق.
حتى ، يتم تقديم المزيد من التفاصيل هنا وهنا.
تعال الآن إلى إجابات سؤالك.
إلى أي مدى يتم التحكم فيها بواسطة نظام التشغيل أو وقت تشغيل اللغة؟
يخصص نظام التشغيل المكدس لكل مؤشر ترابط على مستوى النظام عند إنشاء الخيط. عادةً ما يتم استدعاء نظام التشغيل بواسطة وقت تشغيل اللغة لتخصيص الكومة للتطبيق.
أكثر من ذلك يمكن العثور عليها هنا.
ما هو نطاقها؟
أعطيت بالفعل في الأعلى.
"يمكنك استخدام المكدس إذا كنت تعرف بالضبط مقدار البيانات التي تحتاج إلى تخصيصها قبل وقت التجميع ، وهي ليست كبيرة جدًا. يمكنك استخدام الكومة إذا كنت لا تعرف بالضبط مقدار البيانات التي ستحتاجها في وقت التشغيل أو إذا تحتاج إلى تخصيص الكثير من البيانات ".
يمكن العثور على المزيد هنا.
ما الذي يحدد حجم كل منها؟
يتم تعيين حجم المكدس بواسطة نظام التشغيل عند إنشاء سلسلة رسائل. يتم تعيين حجم الكومة عند بدء تشغيل التطبيق ، ولكن يمكن أن يزداد حسب الحاجة إلى مساحة (يطلب المُخصص مزيدًا من الذاكرة من نظام التشغيل).
ما الذي يجعل المرء أسرع؟
يعد تخصيص المكدس أسرع بكثير نظرًا لأن كل ما يفعله هو تحريك مؤشر المكدس. باستخدام تجمعات الذاكرة ، يمكنك الحصول على أداء مشابه من تخصيص الكومة ، ولكن هذا يأتي مع تعقيد طفيف وصداع خاص به.
أيضًا ، المكدس مقابل الكومة ليس فقط اعتبار الأداء ؛ يخبرك أيضًا الكثير عن العمر المتوقع للأشياء.
يمكن العثور على التفاصيل من هنا.
|
حسنًا ، ببساطة وباختصار ، تعني أنه مرتب وليس مرتبًا ...!
المكدس: في عناصر المكدس ، تصبح الأشياء فوق بعضها البعض ، مما يعني أنها ستكون أسرع وأكثر كفاءة في المعالجة! ...
لذلك هناك دائمًا فهرس للإشارة إلى عنصر معين ، وستكون المعالجة أيضًا أسرع ، وهناك علاقة بين العناصر أيضًا! ...
الكومة: لا يوجد ترتيب ، ستكون المعالجة أبطأ ويتم إفساد القيم مع عدم وجود ترتيب أو فهرس محدد ... هناك عشوائي ولا توجد علاقة بينهما ... لذلك يمكن أن يختلف وقت التنفيذ والاستخدام ...
أقوم أيضًا بإنشاء الصورة أدناه لإظهار كيف سيبدو:
|
تكديس وكومة وبيانات كل عملية في الذاكرة الافتراضية:
|
في الثمانينيات من القرن الماضي ، انتشرت UNIX مثل الأرانب مع قيام الشركات الكبرى بتدوير شركاتها الخاصة.
كان لدى إكسون واحدة كما فقدت العشرات من الأسماء التجارية في التاريخ.
كانت كيفية وضع الذاكرة وفقًا لتقدير العديد من المنفذين.
تم وضع برنامج C نموذجي بشكل مسطح في الذاكرة مع
فرصة للزيادة عن طريق تغيير قيمة brk ().
عادةً ، كان HEAP أقل بقليل من قيمة brk هذه
وزيادة brk زاد مقدار الكومة المتاحة.
كان المكدس الفردي عادةً منطقة أسفل HEAP والتي كانت عبارة عن مساحة من الذاكرة
لا يحتوي على أي شيء ذي قيمة حتى الجزء العلوي من الكتلة الثابتة التالية من الذاكرة.
كانت هذه الكتلة التالية غالبًا CODE والتي يمكن استبدالها ببيانات المكدس
في واحدة من الاختراقات الشهيرة في عصرها.
كانت كتلة الذاكرة النموذجية واحدة BSS (كتلة من الصفرالقيم)
التي لم يتم صفها عرضيًا في عرض جهة تصنيع واحدة.
وكان آخر عبارة عن بيانات تحتوي على قيم مهيأة ، بما في ذلك السلاسل والأرقام.
والثالث هو كود يحتوي على CRT (وقت تشغيل C) ، ووظائف رئيسية ، ووظائف ، ومكتبات.
أدى ظهور الذاكرة الظاهرية في UNIX إلى تغيير العديد من القيود.
لا يوجد سبب موضوعي لضرورة أن تكون هذه الكتل متجاورة ،
أو ثابت في الحجم ، أو طلب بطريقة معينة الآن.
بالطبع ، قبل UNIX كانت Multics التي لم تكن تعاني من هذه القيود.
فيما يلي رسم تخطيطي يوضح أحد تخطيطات الذاكرة في تلك الحقبة.
|
بضع سنتات: أعتقد أنه سيكون من الجيد رسم ذاكرة رسومية وأكثر بساطة:
الأسهم - تبين مكان نمو المكدس والكومة ، وحجم مكدس العملية له حد ، محدد في نظام التشغيل ، وحدود حجم مكدس مؤشر الترابط بواسطة المعلمات في مؤشر ترابط إنشاء API عادةً. عادةً ما يتم تحديد الكومة من خلال معالجة الحد الأقصى لحجم الذاكرة الظاهرية ، على سبيل المثال 32 بت 2-4 جيجابايت.
طريقة بسيطة جدًا: كومة المعالجة عامة للعملية وجميع الخيوط الداخلية ، وتستخدم لتخصيص الذاكرة في الحالة الشائعة مع شيء مثل malloc ().
المكدس عبارة عن ذاكرة سريعة للتخزين في مؤشرات ومتغيرات إرجاع دالة الحالة العامة ، ومعالجتها كمعلمات في استدعاء الوظيفة ، ومتغيرات الوظيفة المحلية.
|
نظرًا لأن بعض الإجابات كانت متقنة ، سأساهم في الحلم.
بشكل مفاجئ ، لم يذكر أحد أن مكدسات استدعاء متعددة (أي لا تتعلق بعدد سلاسل عمليات التشغيل على مستوى نظام التشغيل) لا توجد فقط في اللغات الغريبة (PostScript) أو المنصات (Intel Itanium) ، ولكن أيضًا في الألياف والخيوط الخضراء وبعض تطبيقات الكوروتين.
تتشابه الألياف والخيوط الخضراء والكوروتين من نواحٍ عديدة ، مما يؤدي إلى الكثير من الالتباس. الفرق بين الألياف والخيوط الخضراء هو أن الأول يستخدم تعدد المهام التعاوني ، في حين أن الأخير قد يتميز إما بواحد تعاوني أو استباقي (أو حتى كليهما). للتمييز بين الألياف والكوروتين ، انظر هنا.
على أي حال ، فإن الغرض من كل من الألياف والخيوط الخضراء و coroutines هو وجود وظائف متعددة يتم تنفيذها بشكل متزامن ، ولكن ليس بالتوازي (انظر سؤال SO هذا للتمييز) داخل مؤشر ترابط واحد على مستوى OS ، ونقل التحكم ذهابًا وإيابًا من بعضها البعض بطريقة منظمة.
عند استخدام الألياف أو الخيوط الخضراء أو الكوروتينات ، عادة ما يكون لديك كومة منفصلة لكل وظيفة. (من الناحية الفنية ، ليس مجرد مكدس ولكن سياق كامل للتنفيذ لكل وظيفة. والأهم من ذلك ، سجلات وحدة المعالجة المركزية.) لكل مؤشر ترابط ، هناك العديد من الحزم حيث توجد وظائف تعمل بشكل متزامن ، ويتم التبديل بين تنفيذ كل وظيفة حسب منطق برنامجك. عند تشغيل دالة إلى نهايتها ، يتم إتلاف مكدسها. لذا ، فإن عدد الحزم وأعمارها ديناميكية ولا يتم تحديدها من خلال عدد سلاسل العمليات على مستوى نظام التشغيل!
لاحظ أنني قلت "عادةً ما يكون لديك مكدس منفصل لكل وظيفة". هناك تطبيقات مكدسة وغير مكدسة للكوروتينات. أبرز تطبيقات C ++ المكدسة هي Boost.Coroutine و Microsoft PPL's ​​async / wait. (ومع ذلك ، فإن وظائف C ++ القابلة للاستئناف (المعروفة أيضًا باسم "غير المتزامن والانتظار") ، والتي تم اقتراحها على C ++ 17 ، من المحتمل أن تستخدم coroutines غير مكدس.)
اقتراح الألياف لمكتبة C ++ القياسية قادم. أيضًا ، هناك بعض مكتبات الجهات الخارجية. تحظى الخيوط الخضراء بشعبية كبيرة في لغات مثل Python و Ruby.
|
لدي شيء أشاركه ، على الرغم من تغطية النقاط الرئيسية بالفعل.
كومة
وصول سريع جدا.
مخزنة في ذاكرة الوصول العشوائي.
يتم تحميل استدعاءات الوظائف هنا جنبًا إلى جنب مع المتغيرات المحلية ومعلمات الوظيفة التي تم تمريرها.
يتم تحرير الفضاء تلقائيًا عندما يخرج البرنامج عن النطاق.
مخزنة في ذاكرة متسلسلة.
كومة
وصول بطيء نسبيًا إلى Stack.
مخزنة في ذاكرة الوصول العشوائي.
يتم تخزين المتغيرات التي تم إنشاؤها ديناميكيًا هنا ، والتي تتطلب لاحقًا تحرير الذاكرة المخصصة بعد الاستخدام.
يتم تخزينها في أي مكان يتم فيه تخصيص الذاكرة ، ويتم الوصول إليها بواسطة المؤشر دائمًا.
ملاحظة مثيرة للاهتمام:
إذا تم تخزين استدعاءات الوظائف في كومة ، فقد أدى ذلك إلى نقطتين فوضويتين:
نظرًا للتخزين المتسلسل في المكدس ، يكون التنفيذ أسرع. كان من الممكن أن يؤدي التخزين في الكومة إلى استهلاك كبير للوقت مما يجعل تنفيذ البرنامج بأكمله أبطأ.
إذا تم تخزين الوظائف في كومة (يشير التخزين الفوضوي بمؤشر) ، فلن تكون هناك طريقة للعودة إلى عنوان المتصل مرة أخرى (التي يعطيها المكدس بسبب التخزين المتسلسل في الذاكرة).
|
رائع! الكثير من الإجابات ولا أعتقد أن أحدًا منهم قد فهمها ...
1) أين وماذا هم (فعليًا في ذاكرة الكمبيوتر الحقيقية)؟
المكدس هو الذاكرة التي تبدأ بأعلى عنوان ذاكرة مخصص لصورة البرنامج ، ثم تنخفض قيمتها من هناك. إنه محجوز لمعلمات الوظيفة المسماة ولجميع المتغيرات المؤقتة المستخدمة في الوظائف.
هناك نوعان من أكوام: العامة والخاصة.
تبدأ الكومة الخاصة عند حد 16 بايت (لبرامج 64 بت) أو حد 8 بايت (لبرامج 32 بت) بعد آخر بايت من التعليمات البرمجية في برنامجك ، ثم تزيد فيقيمة من هناك. ويسمى أيضًا الكومة الافتراضية.
إذا أصبحت الكومة الخاصة كبيرة جدًا ، فسوف تتداخل مع مساحة المكدس ، كما سيتداخل المكدس مع الكومة إذا أصبحت كبيرة جدًا. نظرًا لأن المكدس يبدأ من عنوان أعلى ويعمل في طريقه لأسفل إلى العنوان الأدنى ، فمن خلال القرصنة المناسبة ، يمكنك جعل المكدس كبيرًا جدًا بحيث يتجاوز منطقة الكومة الخاصة ويتداخل مع منطقة الرمز. الحيلة إذن هي تداخل ما يكفي من منطقة الكود بحيث يمكنك ربطها في الكود. إنه أمر صعب بعض الشيء وقد تخاطر بتعطل البرنامج ، لكنه سهل وفعال للغاية.
تتواجد الكومة العامة في مساحة الذاكرة الخاصة بها خارج مساحة صورة البرنامج. هذه هي الذاكرة التي سيتم سحبها من القرص الصلب إذا ندرة موارد الذاكرة.
2) إلى أي مدى يتم التحكم فيها بواسطة نظام التشغيل أو وقت تشغيل اللغة؟
يتم التحكم في المكدس بواسطة المبرمج ، ويتم إدارة الكومة الخاصة بواسطة نظام التشغيل ، ولا يتم التحكم في الكومة العامة من قبل أي شخص لأنها خدمة نظام تشغيل - فأنت تقدم الطلبات وإما يتم منحها أو رفضها.
2 ب) ما هو نطاقها؟
كلها عالمية بالنسبة للبرنامج ، لكن محتوياتها يمكن أن تكون خاصة أو عامة أو عالمية.
2 ج) ما الذي يحدد حجم كل منها؟
يتم تحديد حجم المكدس والكومة الخاصة من خلال خيارات وقت تشغيل المترجم. يتم تهيئة الكومة العامة في وقت التشغيل باستخدام معلمة حجم.
2 د) ما الذي يجعل المرء أسرع؟
لم يتم تصميمها لتكون سريعة ، فهي مصممة لتكون مفيدة. كيف يستخدمها المبرمج لتحديد ما إذا كانت "سريعة" أو "بطيئة"
المرجع:
https://norasandler.com/2019/02/18/Write-a-Compiler-10.html
https://docs.microsoft.com/ar-us/windows/desktop/api/heapapi/nf-heapapi-getprocessheap
https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapapi-heapcreate
|
الكثير من الإجابات صحيحة كمفاهيم ، ولكن يجب أن نلاحظ أن الجهاز يحتاج إلى مكدس (أي المعالج الدقيق) للسماح باستدعاء الإجراءات الفرعية (CALL في لغة التجميع ..). (سوف يسميها شباب OOP الأساليب)
في المكدس ، يمكنك حفظ عناوين الإرجاع واستدعاء → push / ret → pop تتم إدارتها مباشرة في الأجهزة.
يمكنك استخدام المكدس لتمرير المعلمات .. حتى لو كان أبطأ من استخدام السجلات (هل سيقول خبير المعالجات الدقيقة أو كتاب BIOS جيد من الثمانينيات ...)
بدون كومة لا يمكن للمعالج الدقيق العمل. (لا يمكننا تخيل برنامج ، حتى في لغة التجميع ، بدون إجراءات فرعية / وظائف)
بدون الكومة يمكن. (يمكن أن يعمل برنامج لغة التجميع بدونه ، حيث أن الكومة هي مفهوم نظام التشغيل ، مثل malloc ، أي استدعاء OS / Lib.
استخدام المكدس أسرع على النحو التالي:
هي الأجهزة ، وحتى الدفع / البوب ​​فعالة للغاية.
يتطلب malloc الدخول إلى وضع kernel ، واستخدام القفل / السيمافور (أو غيرها من أساسيات المزامنة) تنفيذ بعض التعليمات البرمجية وإدارة بعض الهياكل اللازمة لتتبع التخصيص.
|
الكومة هي منطقة من الذاكرة المخصصة ديناميكيًا والتي تتم إدارتها تلقائيًا بواسطة نظام التشغيل أو مكتبة مدير الذاكرة. يمكنك تخصيص كتلة في أي وقت وتحريرها في أي وقت. يتطلب تخصيص الكومة الاحتفاظ بسجل كامل لما يتم تخصيصه وما هو غير ذلك ، بالإضافة إلى بعض الصيانة العامة لتقليل التجزئة ، والعثور على أجزاء ذاكرة متجاورة كبيرة بما يكفي لتناسب الحجم المطلوب ، وما إلى ذلك. يمكن إلغاء تخصيص الذاكرة في أي وقت مع ترك مساحة خالية. مع نمو الكومة ، غالبًا ما يتم تخصيص الكتل الجديدة من العناوين الأقل نحو العناوين الأعلى. وبالتالي يمكنك التفكير في الكومة على أنها كومة من كتل الذاكرة التي تنمو في الحجم مع تخصيص الذاكرة. إذا كانت الكومة صغيرة جدًا بالنسبة للتخصيص ، فيمكن غالبًا زيادة الحجم عن طريق الحصول على ذاكرة أكبر من نظام التشغيل الأساسي. ستبقى الذاكرة المخصصة من كومة الذاكرة المؤقتة مخصصة حتى يحدث أحد الإجراءات التالية:
يتم تحرير الذاكرة
ينتهي البرنامج
كومة:
مخزنة في ذاكرة الوصول العشوائي للكمبيوتر تمامًا مثل الكومة.
ستخرج المتغيرات التي تم إنشاؤها في المكدس خارج النطاق وسيتم إلغاء تخصيصها تلقائيًا.
أسرع بكثير في التخصيص بالمقارنة مع المتغيرات الموجودة على الكومة.
يخزن البيانات المحلية وعناوين الإرجاع المستخدمة لتمرير المعلمات.
يمكن أن يكون لها تجاوز للمكدس عند استخدام الكثير من المكدس (غالبًا
من العودية اللانهائية أو العميقة جدًا ، عمليات تخصيص كبيرة جدًا).
يمكنك استخدام المكدس إذا كنت تعرف بالضبط مقدار البيانات التي تحتاجها
التخصيص قبل وقت الترجمة وهو ليس كبيرًا جدًا.
عادة ما يكون الحد الأقصى للحجم محددًا بالفعل عند برنامجك
يبدأ.
كومة:
مخزنة في ذاكرة الوصول العشوائي للكمبيوتر تمامًا مثل المكدس.
في C ++ ، يجب تدمير المتغيرات الموجودة في الكومة يدويًا وليس أبدًا
تقع خارج النطاق.
يتم تحرير البيانات مع حذف أو حذف [] أو مجانًا.
أبطأ في التخصيص بالمقارنة مع المتغيرات على المكدس.
تستخدم عند الطلب لتخصيص كتلة من البيانات ليستخدمها البرنامج.
يمكن أن يكون هناك تجزئة عندما يكون هناك الكثير من التخصيصات و
التخصيصات.
في C ++ أو C ، سيتم الإشارة إلى البيانات التي تم إنشاؤها على الكومة بواسطة المؤشرات
وتخصص مع جديد أو malloc على التوالي.
يمكن أن يكون هناك فشل في التخصيص إذا تم طلب مخزن مؤقت كبير جدًا
يتم تخصيصها.
أنتسيستخدم الكومة إذا كنت لا تعرف بالضبط مقدار البيانات التي لديك
في وقت التشغيل أو إذا كنت بحاجة إلى تخصيص الكثير من البيانات.
مسؤول عن تسرب الذاكرة.
|
المكدس هو في الأساس ذاكرة يسهل الوصول إليها تدير عناصرها ببساطة
كمكدس جيد. فقط العناصر التي يُعرف حجمها مسبقًا يمكن وضعها في المكدس. هذا هو الحال بالنسبة للأرقام ، السلاسل ، القيم المنطقية.
الكومة هي ذاكرة للعناصر التي لا يمكنك تحديدها مسبقًا
الحجم والهيكل الدقيق. نظرًا لأنه يمكن تحوير الكائنات والمصفوفات و
التغيير في وقت التشغيل ، عليهم الذهاب إلى الكومة.
المصدر: Academind
|
ترتبط مكدس وحدة المعالجة المركزية (CPU) وكومة الذاكرة المؤقتة (CPU) فعليًا بكيفية عمل وحدة المعالجة المركزية والسجلات مع الذاكرة ، وكيفية عمل لغة تجميع الآلة ، وليس باللغات عالية المستوى نفسها ، حتى لو كان بإمكان هذه اللغات تحديد أشياء صغيرة.
تعمل جميع وحدات المعالجة المركزية الحديثة مع "نفس" نظرية المعالجات الدقيقة: فهي تستند جميعها إلى ما يسمى "السجلات" وبعضها مخصص لـ "المكدس" للحصول على الأداء. تحتوي جميع وحدات المعالجة المركزية (CPU) على سجلات مكدس منذ البداية وكانت دائمًا هنا ، كما أعلم. لغات التجميع هي نفسها منذ البداية ، على الرغم من الاختلافات ... حتى Microsoft ولغتها المتوسطة (IL) التي غيرت النموذج ليكون لها لغة تجميع جهاز ظاهري OO. لذلك سنكون قادرين على الحصول على بعض وحدة المعالجة المركزية CLI / CIL في المستقبل (مشروع واحد من MS).
تحتوي وحدات المعالجة المركزية (CPU) على سجلات مكدس لتسريع الوصول إلى الذكريات ، ولكنها محدودة مقارنة باستخدام المسجلات الأخرى للوصول الكامل إلى كل الذاكرة المتاحة للعملية. لهذا السبب تحدثنا عن تخصيصات المكدس والكوم.
باختصار ، وبشكل عام ، فإن الكومة عبارة عن hudge وبطيئة وهي مخصصة للمثيلات "العالمية" ومحتوى الكائنات ، حيث أن المكدس صغير وسريع وللمتغيرات والمراجع "المحلية" (المؤشرات المخفية تنسى إدارتها).
لذلك عندما نستخدم الكلمة الأساسية الجديدة في طريقة ما ، يتم إنشاء المرجع (int) في المكدس ، ولكن يتم إنشاء الكائن وجميع محتوياته (أنواع القيم وكذلك الكائنات) في الكومة ، إذا كنت أتذكر. ولكن يتم إنشاء أنواع ومصفوفات القيم الأولية المحلية في المكدس.
يكمن الاختلاف في الوصول إلى الذاكرة في المستوى المرجعي للخلايا: تتطلب معالجة الكومة ، الذاكرة الإجمالية للعملية ، تعقيدًا أكثر من حيث التعامل مع سجلات وحدة المعالجة المركزية ، من المكدس الذي يكون "أكثر" محليًا من حيث المعالجة نظرًا لأن مكدس وحدة المعالجة المركزية يستخدم السجل كعنوان أساسي ، إذا كنت أتذكر.
هذا هو السبب في أنه عندما يكون لدينا مكالمات أو حلقات متكررة طويلة جدًا أو غير محدودة ، نحصل على تجاوز سعة المكدس بسرعة ، دون تجميد النظام على أجهزة الكمبيوتر الحديثة ...
C # Heap (ing) Vs Stack (ing) في .NET
Stack vs Heap: تعرف على الفرق
تخصيص ذاكرة الفئة الثابتة حيث يتم تخزينها C #
ما وأين هي المكدس والكومة؟
https://en.wikipedia.org/wiki/Memory_management
https://en.wikipedia.org/wiki/Stack_register
موارد لغة التجميع:
دروس برمجة التجميع
أدلة مطوري برامج معماريات Intel® 64 و IA-32
|
شكرًا لك على مناقشة جيدة حقًا ، ولكن بصفتك مستجدًا حقيقيًا ، أتساءل أين يتم حفظ التعليمات؟ في البداية ، كان العلماء يقررون بين بنيتين (فون نيومان حيث يعتبر كل شيء DATA و HARVARD حيث تم حجز مساحة من الذاكرة للتعليمات وأخرى للبيانات). في النهاية ، اخترنا تصميم von Neumann والآن يعتبر كل شيء "كما هو". جعل هذا الأمر صعبًا بالنسبة لي عندما كنت أتعلم التجميع
https://www.cs.virginia.edu/~evans/cs216/guides/x86.html
لأنهم يتحدثون عن السجلات ومؤشرات المكدس.
كل شيء أعلاه يتحدث عن البيانات. أعتقد أنه نظرًا لأن التعليمات هي شيء محدد له أثر ذاكرة معين ، فسيتم وضعها في المكدس ، وبالتالي فإن جميع سجلات "تلك" التي تمت مناقشتها في التجميع موجودة في المكدس. بالطبع بعد ذلك جاءت البرمجة الموجهة للكائنات مع التعليمات والبيانات التي تم إدخالها في هيكل كان ديناميكيًا ، لذا سيتم الاحتفاظ بالتعليمات في الكومة أيضًا؟
|
سؤال نشط للغاية. اكسب 10 سمعة للإجابة على هذا السؤال. تساعد متطلبات السمعة في حماية هذا السؤال من البريد العشوائي ونشاط عدم الإجابة.
ليس الجواب الذي تبحث عنه؟ تصفح الأسئلة الأخرى الموسومة بعلامات إدارة الذاكرة كومة حيادية اللغة تخصيص الذاكرة الديناميكية أو اطرح سؤالك الخاص.